////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_NETWORKING_WINDOWS_HEADER_H__
#define __WN_NETWORKING_WINDOWS_HEADER_H__

static WN_VOID* IOCPThread(WN_VOID* _networkManager);
static WN_VOID* ListenThread(WN_VOID* _networkManager);

HANDLE mIOCP;
WSAEVENT mAcceptEvent;
WSAEVENT mShutdownEvent;
WSAData mWSAData;

class WNConnectionData {
public:
    enum OverlapOperation{
        ReadOp,
        WriteOp,
        NoOp
    };
    WNConnectionData(WNNetworkManager& _manager):
        mManager(_manager),
        mSocket(INVALID_SOCKET),
        mReadHead(0),
        mProcessedHead(0),
        mExpectedData(0),
        mLeftoverData(0),
        mProcessedData(0),
        mCurrentReadBuffer(_manager),
        mSending(WN_FALSE),
        mAddress(WN_NULL){
        ZeroMemory(&mSendOverlap, sizeof(WSAOVERLAPPED));
        ZeroMemory(&mReceiveOverlap, sizeof(WSAOVERLAPPED));
        mCurrentReadBuffer.Clear();
        mReadBuffers.push_back(WNContainers::WNAllocateResource<WNBufferResource>(_manager));
    }

    WN_VOID SetSocket(SOCKET _socket) {
        mSocket = _socket;
    }

    WN_VOID SetAddress(const WN_CHAR* _address) {
        mAddress = _address;
    }

    const WN_CHAR* GetAddress() {
        return(mAddress);
    }

    OverlapOperation GetOperation(WSAOVERLAPPED* overlapped) {
        if(&mSendOverlap == overlapped) {
            return(WriteOp);
        } else if (&mReceiveOverlap == overlapped) {
            return(ReadOp);
        }
        return(NoOp);
    }
    WN_BOOL Receive();
    WN_VOID Send();
    WN_VOID AppendSendBuff(WNNetworkWriteBuffer& _buff);
    WN_BOOL ProcessSend();
    WN_VOID ProcessRead(WN_SIZE_T _readSize);
    WN_VOID ProcessWrite();
    WN_VOID SetHandle(WNConnectionHandle& handle) {
        mHandle = handle;
    }
    WNConnectionHandle GetHandle() {
        return(mHandle);
    }
    WN_VOID SetCallback(WNCallback2<WN_BOOL, WNConnectionHandle, const WN_CHAR*>& callback) {
        mConnectedCallback = callback;
    }

    const WNCallback2<WN_BOOL, WNConnectionHandle, const WN_CHAR*>& GetCallback() {
        return(mConnectedCallback);
    }
private:
    WNConnectionHandle mHandle;
    WNCallback2<WN_BOOL, WNConnectionHandle, const WN_CHAR*> mConnectedCallback;
    WNConcurrency::WNCriticalSection mWriteBufferLock;
    SOCKET mSocket;
    WSAOVERLAPPED mSendOverlap;
    WSAOVERLAPPED mReceiveOverlap;
    std::deque<WNContainers::WNResourcePointer<WNBufferResource> > mReadBuffers;
    std::vector<WSABUF> mWSAWriteBuffers;
    WNNetworkManager& mManager;
    WNNetworkReadBuffer mCurrentReadBuffer;
    std::deque<WNNetworkWriteBuffer> mWriteBuffers;
    WN_BOOL mSending;
    const WN_CHAR* mAddress;
    WN_SIZE_T mReadHead;
    WN_SIZE_T mProcessedHead;
    WN_SIZE_T mExpectedData;
    WN_SIZE_T mLeftoverData;
    WN_SIZE_T mProcessedData;
    WN_UINT32 mCallbackFunction;
    WN_CHAR mLeftover[7];

};

std::map<SOCKET, WNCallback2<WN_BOOL, WNConnectionHandle, const WN_CHAR*> > mListeningSockets;

WNConcurrency::WNCriticalSection mListenSection;

enum WNInitializationStates {
    WN_NOT_STARTED,
    WN_WSA_STARTUP,
    WN_ACCEPT_EVENT_CREATED,
    WN_SHUTDOWN_EVENT_CREATED,
    WN_IOCP_CREATED,
    WN_THREADS_CREATED,
    WN_LISTEN_THREAD_CREATED,
    WN_INITIALIZATION_COMPLETE
};

WNInitializationStates mInitializationState;

#endif//__WN_NETWORKING_WINDOWS_HEADER_H__